package interaction

import (
	"time"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/sysparam"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/infod"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"

	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/factory"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/interactiond"
)

type respFollow struct {
	ID         string    `json:"id"`          // 互动ｉｄ
	UID        string    `json:"uid"`         // 互动用户
	Status     int       `json:"status"`      // 状态　1 已经关注　2 未关注　3 互相关注
	FollowTime time.Time `json:"follow_time"` // 关注时间
}

func (c interactionCtrl) putFollow(ctx *gin.Context) {
	code := sysparam.IntsFollowCode()
	// 互动主题类型　用户
	iityp := interactiond.IGTTPerson
	id := ctx.Param("id")
	if id == "" {
		c.ErrBadRequest(ctx, 1, "参数错误")
		return
	}
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "保存失败：未登录")
		return
	}

	if uinfo, err := c.OperHandler(ctx).GetUser(id); err != nil || uinfo == nil {
		c.ErrBadRequest(ctx, 10, "被关在用户不存在")
		return
	}
	if err := c.addOp(dctx, uid, code, reqOp{
		TargetID:   id,
		TargetType: iityp,
		Value:      1,
	}); err != nil {
		c.ErrServerError(ctx, 6, "关注失败", err)
		return
	}
	c.Success(ctx, nil)
}
func (c interactionCtrl) deleteFollow(ctx *gin.Context) {
	code := sysparam.IntsFollowCode()
	iityp := interactiond.IGTTPerson
	id := ctx.Param("id")
	if id == "" {
		c.ErrBadRequest(ctx, 1, "参数错误")
		return
	}
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "取消关注失败：未登录")
		return
	}
	if err := c.deleteOp(dctx, uid, code, reqOp{
		TargetID:   id,
		TargetType: iityp,
	}); err != nil {
		c.ErrServerError(ctx, 5, "取消关注失败", errors.Wrapf(err, "取消关注失败"))
		return
	}
	c.Success(ctx, nil)
}

func (c interactionCtrl) queryPageMyFans(ctx *gin.Context) {
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "保存失败：未登录")
		return
	}
	code := sysparam.IntsFollowCode()

	g, err := factory.DefaultFactory.GetOrCreIGroup(dctx, interactiond.IGTTPerson, uid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查询失败", errors.Wrapf(err, "查询或创建互动组信息失败"))
		return
	}

	sch := interactiond.InteractionSearch{
		Codes: []string{code},
		IGID:  []string{g.IGID},
	}
	page := c.GetPageInfo(ctx, common.PageModeID)
	pr, cs, err := c.iiar.QueryPage(dctx, sch, page)
	if err != nil {
		c.ErrServerError(ctx, 30, "查询失败", errors.Wrapf(err, "查询互动交互列表失败"))
		return
	}
	l := len(cs)
	out := make([]*respFollow, 0, l)
	if l == 0 {
		c.SuccessPage(ctx, page, pr, out)
		return
	}
	igids := make([]string, 0, l)
	cmap := make(map[string]*respFollow)
	for _, v := range cs {
		rc := &respFollow{
			ID:         v.InteractionID,
			UID:        v.UID,
			FollowTime: v.CreTime,
			Status:     2,
		}
		igid := c.igar.ID(interactiond.IGTTPerson, v.UID)
		igids = append(igids, igid)
		cmap[v.UID] = rc
		out = append(out, rc)
	}
	sch = interactiond.InteractionSearch{
		Codes: []string{code},
		UID:   []string{uid},
		IGID:  igids,
	}
	page2 := common.PageInfo{
		PageSize: page.PageSize,
	}
	_, cs, err = c.iiar.QueryPage(dctx, sch, page2)
	if err != nil {
		c.ErrServerError(ctx, 30, "查询失败", errors.Wrapf(err, "查询是否被关注"))
		return
	}
	for _, v := range cs {
		if v.Value == 1 {
			cmap[v.IGID[4:]].Status = 3
		}
	}
	c.SuccessPage(ctx, page, pr, out)
}

func (c interactionCtrl) queryPageMyFollow(ctx *gin.Context) {
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "保存失败：未登录")
		return
	}
	code := sysparam.IntsFollowCode()

	g, err := factory.DefaultFactory.GetOrCreIGroup(dctx, interactiond.IGTTPerson, uid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查询失败", errors.Wrapf(err, "查询或创建互动组信息失败"))
		return
	}
	// 我的关注者查询
	sch := interactiond.InteractionSearch{
		Codes: []string{code},
		UID:   []string{uid},
	}
	page := c.GetPageInfo(ctx, common.PageModeID)
	pr, cs, err := c.iiar.QueryPage(dctx, sch, page)
	if err != nil {
		c.ErrServerError(ctx, 30, "查询失败", errors.Wrapf(err, "查询互动交互列表失败"))
		return
	}
	if len(cs) == 0 {
		c.SuccessPage(ctx, page, pr, []string{})
	}
	out := make([]*respFollow, 0, len(cs))
	uids := make([]string, 0, len(cs))
	cmap := make(map[string]*respFollow)
	for _, v := range cs {
		targetID := v.IGID[4:]
		rc := &respFollow{
			ID:         v.InteractionID,
			UID:        targetID,
			FollowTime: v.CreTime,
			Status:     1,
		}
		//igid := c.igar.ID(interactiond.IGTTPerson, v.UID)
		uids = append(uids, targetID)
		cmap[targetID] = rc
		out = append(out, rc)
	}
	sch = interactiond.InteractionSearch{
		Codes: []string{code},
		UID:   uids,
		IGID:  []string{g.IGID},
	}
	page2 := common.PageInfo{
		PageSize: page.PageSize,
	}
	_, cs, err = c.iiar.QueryPage(dctx, sch, page2)
	if err != nil {
		c.ErrServerError(ctx, 30, "查询失败", errors.Wrapf(err, "查询是否被关注"))
		return
	}
	for _, v := range cs {
		if v.Value == 1 {
			// TODO: 有可能空指针还没找到逻辑问题，理论上不应该出现空指针
			if cmap[v.UID] != nil {

				cmap[v.UID].Status = 3
			} else {
				log.Errorf("不应该发生的错误需要修改:%v", v)
			}
		}
	}
	c.SuccessPage(ctx, page, pr, out)
}

type respUserFollow struct {
	Fans     int `json:"fans"`      // 粉丝数
	Follows  int `json:"follows"`   //　关注数
	IsFollow int `json:"is_follow"` //　是否关注
}

func (c interactionCtrl) queryUserFollow(ctx *gin.Context) {
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	// if uid == "" {
	// 	c.ErrUnauthorized(ctx, "保存失败：未登录")
	// 	return
	// }
	code := sysparam.IntsFollowCode()
	otheruid := ctx.Param("uid")
	if otheruid == "" {
		c.ErrBadRequest(ctx, 1, "未指定查询用户")
		return
	}
	// 用户的粉丝数　用户关注数

	g, err := factory.DefaultFactory.GetOrCreIGroup(dctx, interactiond.IGTTPerson, otheruid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查询失败", errors.Wrapf(err, "查询或创建互动组信息失败"))
		return
	}
	resp := respUserFollow{
		IsFollow: -1,
	}
	// 获取粉丝数
	for _, v := range g.GroupTotal {
		if v.ITCode == code {
			resp.Fans = v.Total
			break
		}
	}

	// 获取关注数
	resp.Follows, err = c.iiar.QueryNum(dctx, interactiond.InteractionSearch{
		Codes: []string{code},
		UID:   []string{otheruid},
	})
	if err != nil {
		c.ErrServerError(ctx, 3, "查询失败", errors.Wrapf(err, "查询%v粉丝数失败", otheruid))
		return
	}

	// 查询我是否关注过该用户
	if uid != "" {
		n, err := c.iiar.QueryNum(dctx, interactiond.InteractionSearch{
			Codes: []string{code},
			IGID:  []string{c.igar.ID(interactiond.IGTTPerson, otheruid)},
			UID:   []string{uid},
		})
		if err != nil {
			c.ErrServerError(ctx, 4, "查询失败", errors.Wrapf(err, "查询%v是否关注过该用户失败", uid, otheruid))
			return
		}
		if n == 1 {
			resp.IsFollow = 1
		} else {
			resp.IsFollow = 0
		}
	}
	c.Success(ctx, resp)
}

type respMyNums struct {
	Follows int `json:"follows"`
	Fans    int `json:"fans"`
	Coll    int `json:"coll"`
	Ints    int `json:"ints"`
}

func (c interactionCtrl) queryMyNums(ctx *gin.Context) {
	intsColumnid := sysparam.IntsColumnid()
	dctx := c.DDDContext(ctx)
	uid := dctx.UID()
	if uid == "" {
		c.ErrUnauthorized(ctx, "查询失败：未登录")
		return
	}
	code := sysparam.IntsFollowCode()

	// 用户的粉丝数　用户关注数
	g, err := factory.DefaultFactory.GetOrCreIGroup(dctx, interactiond.IGTTPerson, uid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查询失败", errors.Wrapf(err, "查询或创建互动组信息失败"))
		return
	}
	resp := respMyNums{}
	// 获取粉丝数
	for _, v := range g.GroupTotal {
		switch v.ITCode {
		case code:
			resp.Fans = v.Total
			// case intTypeCollCode:
			// 	resp.Coll = v.Total
		}
	}
	// 获取关注数
	if resp.Follows, err = c.iiar.QueryNum(dctx, interactiond.InteractionSearch{
		Codes: []string{code},
		UID:   []string{uid},
	}); err != nil {
		c.ErrServerError(ctx, 3, "查询失败", errors.Wrapf(err, "查询%v粉丝数失败", uid))
		return
	}
	// 获取收藏
	if resp.Coll, err = c.iiar.QueryNum(dctx, interactiond.InteractionSearch{
		Codes: []string{sysparam.IntsCollectionCode()},
		UID:   []string{uid},
	}); err != nil {
		c.ErrServerError(ctx, 3, "查询失败", errors.Wrapf(err, "查询%v粉丝数失败", uid))
		return
	}
	if resp.Ints, err = c.iar.QueryNum(dctx, infod.InfoSearch{
		ColumnID: intsColumnid,
		Creator:  uid,
		Status:   []infod.IStatus{infod.IStatusPublished},
	}); err != nil {
		c.ErrServerError(ctx, 4, "查询失败", errors.Wrapf(err, "查询%v互动数量失败", uid))
		return
	}
	c.Success(ctx, resp)
}
